import Big from 'big.js';
import { useCallback, useEffect } from 'react';

/**
 * 引用big.js封装常用计算方法,并同时为String和Number对象提供方法
 * author: xugq
 * date: 2022-09-22
 *
 * plus 加  minus减  times乘  div除  toFixed四舍五入保留位数
 */

type T = string | number;

type MethodName = 'plus' | 'minus' | 'times' | 'div'

declare global {
  interface String {
    plus: (...arg: Array<T>) => number
    minus: (...arg: Array<T>) => number
    times: (...arg: Array<T>) => number
    div: (...arg: Array<T>) => number
  }

  interface Number {
    plus: (...arg: Array<T>) => number
    minus: (...arg: Array<T>) => number
    times: (...arg: Array<T>) => number
    div: (...arg: Array<T>) => number
  }
}


const useBig = () => {
  const methods: MethodName[] = ['plus', 'minus', 'times', 'div'];

  function bigCalc(methodName: MethodName, arg: Array<T>, val?: T) {
    if (arg.length === 0) return 0;
    return Number(arg.reduce((prev: T, next: T) => new Big(prev)[methodName](next).toString(), val ?? 0));
  }

  /* String扩展属性 */
  const stringAttribute = useCallback(() => {
    methods.forEach(methodName => {
      if(typeof String.prototype[methodName] === "undefined") {
        String.prototype[methodName] = function(...arg: Array<T>) {
          return Number(new Big(bigCalc(methodName, arg, this as T)).toFixed(2));
        }
      }
    })
  },[])

  /* Number扩展属性 */
  const numberAttribute = useCallback(() => {
    methods.forEach(methodName => {
      if(typeof Number.prototype[methodName] === "undefined") {
        Number.prototype[methodName] = function(...arg: Array<T>) {
          return Number(new Big(bigCalc(methodName, arg, this as T)).toFixed(2));
        }
      }
    })
  },[])

  useEffect(() => {
    stringAttribute();
    numberAttribute();
  }, [])

  return {
    plus: (...arg: Array<T>) => bigCalc('plus', arg),
    minus: (...arg: Array<T>) => bigCalc('minus', arg),
    times: (...arg: Array<T>) => bigCalc('times', arg),
    div: (...arg: Array<T>) => bigCalc('div', arg),
    toFixed: (value: T, dp?: number) => new Big(value).toFixed(dp ?? 2),
  };
};

export default useBig;
